<!-- banner图 -->
<template>
	<div class="banner">
		<transition name="fade">
			<div class="top_header_banner" v-if="bannerShow">
				<div
					class="animated_banner"
					@mousemove="handleMouseMove"
					@mouseover="handleMouseOver"
					@mouseleave="handleMouseLeave"
				>
					<div
						class="layer"
						v-for="item in layers"
						:key="item.resources"
						:style="{ transform: `matrix(${item.transform.toString()})`, opacity: `${item.opacity || 1}` }"
					>
						<img
							:src="item.url"
							v-if="!/\.(webm|mp4)$/.test(item.url)"
							:style="{ filter: `blur(${item.blur}px)`, width: `${item.width}px` }"
						/>
						<!-- <video :src="item.resources[0].src" muted loop autoplay playsInline style="object-fit: cover;" v-else /> -->
					</div>
				</div>
				<a @click="bannerShow = !bannerShow" class="banner_close">×</a>
			</div>
		</transition>
	</div>
</template>

<script setup name="bannerComponent">
	import { baseRequest } from '@/utils/request'
	onBeforeMount(() => {
		// 只有在启用了动画banner的配置，且浏览器支持css filter时才加载动画banner的图片资源
		const animatedBannerSupport =
			typeof CSS !== 'undefined' &&
			CSS.supports &&
			CSS.supports('filter: blur(1px)') &&
			!/^((?!chrome|android).)*safari/i.test(navigator.userAgent)
		// safari浏览器在mac屏幕上模糊效果有性能问题，不开启

		if (!animatedBannerSupport) {
			return //不支持直接返回
		}
		getBannerList()
	})

	const bannerShow = ref(true)
	const request = (url, ...arg) => baseRequest(url, ...arg)
	//获取banner资源
	const getBannerList = () => {
		request('/biz/dynamicbanner/list', {}, 'get').then((res) => {
			res.map((item) => {
				item.transform = item.transform.split(',').map(Number)
				item.transformInitial = item.transform
				item.url = item.src
				if (item.deg) {
					item.deg = Math.PI / item.deg
					item.degInitial = item.deg
				}
				if (item.opacity) {
					item.opacityInitial = item.opacity.split(',').map(Number)
				}
				return item
			})
			layers.value = res
		})
	}

	//a 参数 a 用来代表加速度，不同图层有不同的加速度，加速度越快代表移动幅度越大
	//
	const layers = ref([])

	const initX = ref(0) // 初始值
	const moveX = ref(0) // 偏移值
	const startTime = ref(0)
	const duration = 300 // 动画持续时间（毫秒）
	//该函数接收一个起始值 start 与目标值 end，插值系数：amt是在 0 到 1 之间的值，表示过渡的进度比例
	const lerp = (start, end, amt) => (1 - amt) * start + amt * end // 计算线性插值

	//鼠标进入
	const handleMouseOver = (e) => {
		//在鼠标进入时记录初始化位置
		initX.value = e.pageX
	}

	//鼠标移出
	const handleMouseLeave = () => {
		startTime.value = 0
		requestAnimationFrame(homing) // 开始回弹动画
	}

	//鼠标移动
	const handleMouseMove = (e) => {
		//鼠标移动时减去初始值就得到偏移值
		moveX.value = e.pageX - initX.value
		animate(undefined)
		// requestAnimationFrame(animate)
	}

	//动画回正
	const homing = (timestamp) => {
		!startTime.value && (startTime.value = timestamp)
		const elapsed = timestamp - startTime.value //计算经过时间
		const progress = Math.min(elapsed / duration, 1)
		animate(progress) // 传递动画进度
		progress < 1 && requestAnimationFrame(homing) // 继续下一帧
	}

	//动画执行
	const animate = (progress) => {
		//如果没有数据直接返回
		if (layers.value.length <= 0) return
		const isHoming = typeof progress === 'number'
		for (let i = 0; i < layers.value.length; i++) {
			const layer = layers.value[i]
			let m = new DOMMatrix(layer.transformInitial)
			let move = moveX.value * layer.a // 移动X translateX
			let s = layer.f ? layer.f * moveX.value + 1 : 1 // 放大比例 Scale
			let g = moveX.value * (layer.g || 0) // 移动Y translateY
			if (isHoming) {
				// 回正时处理
				m.e = lerp(moveX.value * layer.a + layer.transformInitial[4], layer.transformInitial[4], progress)
				move = 0
				s = lerp(layer.f ? layer.f * moveX.value + 1 : 1, 1, progress)
				g = lerp(layer.g ? layer.g * moveX.value : 0, 0, progress)
			}
			m = m.multiply(new DOMMatrix([m.a * s, m.b, m.c, m.d * s, move, g]))
			if (layer.deg) {
				// 有旋转角度
				const deg = isHoming ? lerp(layer.degInitial * moveX.value, 0, progress) : layer.degInitial * moveX.value
				m = m.multiply(new DOMMatrix([Math.cos(deg), Math.sin(deg), -Math.sin(deg), Math.cos(deg), 0, 0]))
			}
			if (layer.opacity) {
				// 有透明度变化
				layer.opacity =
					isHoming && moveX.value > 0
						? lerp(layer.opacityInitial[1], layer.opacityInitial[0], progress)
						: lerp(layer.opacityInitial[0], layer.opacityInitial[1], (moveX.value / window.innerWidth) * 2)
			}
			layer.transform = [m.a, m.b, m.c, m.d, m.e, m.f] // 应用所有变换效果
		}
	}
</script>

<style lang="less" scoped>
	.fade-enter-active,
	.fade-leave-active {
		transition: opacity 0.5s;
	}
	.fade-enter, .fade-leave-to /* .fade-leave-active for <=2.1.8 */ {
		opacity: 0;
	}

	.animated_banner {
		position: relative;
		overflow: hidden;
		margin: 0 auto;
		min-width: 1000px;
		min-height: 155px;
		height: 10vw;
		max-height: 240px;
	}

	.layer {
		position: absolute;
		left: 0;
		top: 0;
		height: 100%;
		width: 100%;
		display: flex;
		align-items: center;
		justify-content: center;
	}

	.banner_close {
		position: absolute;
		right: 10px;
		top: 10px;
		background-color: #fff;
		height: 10px;
		line-height: 10px;
	}

	@keyframes fadeToShow {
		0% {
			display: none;
			width: 0;
			height: 0;
		}
		100% {
			display: block;
			width: 340px;
			height: 230px;
		}
	}
</style>
